package org.cerberus.platform.internal.impl;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.cerberus.platform.internal.IObjectGraphTransaction;
import org.cerberus.platform.internal.domain.IComponentClass;


/**
 * @author  chu
 */
public class InMemoryObjectGraphTransaction implements IObjectGraphTransaction {

	/**
	 * @uml.property  name="addClasses"
	 */
	private Map<String, IComponentClass> addClasses;
	/**
	 * @uml.property  name="removeClasses"
	 */
	private List<String> removeClasses;
	/**
	 * @uml.property  name="addObjects"
	 */
	private Map<Integer, Object[]> addObjects;
	/**
	 * @uml.property  name="removeObjects"
	 */
	private List<Integer> removeObjects;
	/**
	 * @uml.property  name="objectChanges"
	 */
	private Map<Integer, Object[]> objectChanges;
	
	public void addComponentClass(IComponentClass clazz) {
		if (addClasses == null) {
			addClasses = new HashMap<String, IComponentClass>();
		}
		if (removeClasses != null 
				&& removeClasses.contains(clazz.getClassID())) {
			removeClasses.remove(clazz.getClassID());
			if (removeClasses.size() == 0) {
				removeClasses = null;
			}
		}
		addClasses.put(clazz.getClassID(), clazz);
	}
	
	public void removeComponentClass(String classID) {
		if (removeClasses == null) {
			removeClasses = new ArrayList<String>();
		}
		if (addClasses != null && addClasses.containsKey(classID)) {
			addClasses.remove(classID);
			if (addClasses.size() == 0) {
				addClasses = null;
			}
		}
		removeClasses.add(classID);
	}
	
	public void addObjectChange(Integer hash, int index, int attributeCount, Object value) {
		if (addObjects != null && addObjects.containsKey(hash)) {
			addObjects.get(hash)[index+1] = value;
			return;
		}
		if (objectChanges == null) {
			objectChanges = new HashMap<Integer, Object[]>();
		}
		Object[] currentChange = objectChanges.get(hash);
		if (currentChange == null) {
			currentChange = new Object[attributeCount+1];
		}
		currentChange[index+1] = value;
	}
	
	public void addObject(Integer hash, Object[] objectData) {
		if (addObjects == null) {
			addObjects = new HashMap<Integer, Object[]>(20, 0.75f);
		}
		addObjects.put(hash, objectData);
	}
	
	public void removeObject(Integer hash) {
		if (removeObjects == null) {
			removeObjects = new ArrayList<Integer>();
		}
		removeObjects.add(hash);
	}
	
	public void removeObjects(Collection<Integer> hashes) {
		if (removeObjects == null) {
			removeObjects = new ArrayList<Integer>();
		}
		removeObjects.addAll(hashes);
	}

	/**
	 * @return
	 * @uml.property  name="addClasses"
	 */
	public Map<String, IComponentClass> getAddClasses() {
		return addClasses;
	}

	/**
	 * @return
	 * @uml.property  name="removeClasses"
	 */
	public List<String> getRemoveClasses() {
		return removeClasses;
	}

	/**
	 * @return
	 * @uml.property  name="addObjects"
	 */
	public Map<Integer, Object[]> getAddObjects() {
		return addObjects;
	}

	/**
	 * @return
	 * @uml.property  name="removeObjects"
	 */
	public List<Integer> getRemoveObjects() {
		return removeObjects;
	}
	
	/**
	 * @return
	 * @uml.property  name="objectChanges"
	 */
	public Map<Integer, Object[]> getObjectChanges() {
		return objectChanges;
	}
	
	public boolean isEmpty() {
		return addClasses == null
		  && removeClasses == null
		  && addObjects == null
		  && removeObjects == null
		  && objectChanges == null;
	}
	
	public InMemoryObjectGraphTransaction mergeWithLater(InMemoryObjectGraphTransaction laterOccuredTransaction) {
		if (laterOccuredTransaction == null) {
			return this;
		}
		if (laterOccuredTransaction.addClasses != null) {
			for (String classID : laterOccuredTransaction.addClasses.keySet()) {
				addComponentClass(laterOccuredTransaction.addClasses.get(classID));
			}
		}
		if (laterOccuredTransaction.removeClasses != null) {
			for (String classID : laterOccuredTransaction.removeClasses) {
				removeComponentClass(classID);
			}
		}
		if (laterOccuredTransaction.addObjects != null) {
			for (int objectID : laterOccuredTransaction.addObjects.keySet()) {
				addObject(objectID, laterOccuredTransaction.addObjects.get(objectID));
			}
		}
		if (laterOccuredTransaction.removeObjects != null) {
			for (int objectID : laterOccuredTransaction.removeObjects) {
				removeObject(objectID);
			}
		}
		
		return this;
	}

	
	
}
